package com.fowo.api.sys.controller;

import com.fowo.api.common.model.R;
import com.fowo.api.common.util.ResponseUtils;
import com.fowo.api.sys.entity.SysFile;
import com.fowo.api.sys.service.FileService;
import com.fowo.api.sys.service.SysFileService;
import com.fowo.api.sys.service.ThumbnailService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;

@Tag(name = "文件上传、下载")
@RequestMapping("/api/file")
@RestController
@Slf4j
public class FileController {
    @Resource
    private SysFileService sysFileService;
    @Resource
    private FileService fileService;
    @Resource
    private ThumbnailService thumbnailService;

    @Operation(summary = "上传文件，返回系统文件对象")
    @PostMapping("upload")
    public R<SysFile> upload(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "ext", required = false) String ext
    ) {
        return R.data(() -> fileService.upload(file, ext));
    }

    @Operation(summary = "显示附件内容")
    @GetMapping("view/{key}")
    public void view(@PathVariable String key, HttpServletResponse response) throws IOException {
        final SysFile sysFile = sysFileService.getByStorageKey(key);
        if (sysFile == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        InputStream inputStream = fileService.read(sysFile);
        if (inputStream != null) {
            response.setContentType(sysFile.getMimeType());
            response.addHeader("Cache-Control", "max-age=300");
            StreamUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    @Operation(summary = "显示附件内容/直接获取，不读取数据库")
    @GetMapping("view/{storageType}/{storageKey}")
    public void view(@PathVariable String storageType, @PathVariable String storageKey, HttpServletResponse response) throws IOException {
        InputStream inputStream = fileService.readDirect(storageType, storageKey);
        if (inputStream != null) {
            response.setContentType(Files.probeContentType(new File(storageKey).toPath()));
            response.addHeader("Cache-Control", "max-age=300");
            StreamUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    @Operation(summary = "显示附件缩略图")
    @GetMapping("view/{key}/thumbnail")
    public void thumbnail(@PathVariable String key, HttpServletResponse response) throws IOException {
        final SysFile sysFile = sysFileService.getByStorageKey(key);
        if (sysFile == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        if (sysFile.getThumbnail() == null) {
            // 生成缩略图
            InputStream inputStream = fileService.read(sysFile);
            if (inputStream == null) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
            try {
                // 生成缩略图
                ByteArrayOutputStream thumbnailBaos = new ByteArrayOutputStream();
                thumbnailService.createThumbnail(320, 320, inputStream, thumbnailBaos);
                inputStream.close();
                byte[] thumbnailByteArray = thumbnailBaos.toByteArray();
                // 保存缩略图
                SysFile updateFile = new SysFile();
                updateFile.setId(sysFile.getId());
                updateFile.setThumbnail(thumbnailByteArray);
                sysFile.setThumbnail(updateFile.getThumbnail());
                sysFileService.updateById(updateFile);
            } catch (Exception e) {
                log.error("生成缩略图失败", e);
                // 更新缩略图字段为空数组，表示不可用，未来不要再次生成
                SysFile updateFile = new SysFile();
                updateFile.setId(sysFile.getId());
                updateFile.setThumbnail(new byte[0]);
                sysFile.setThumbnail(updateFile.getThumbnail());
                sysFileService.updateById(updateFile);
            }
        }
        if (sysFile.getThumbnail() != null && sysFile.getThumbnail().length > 0) {
            // 缩略图，都是 JPG 格式的
            response.setContentType(MimeTypeUtils.IMAGE_JPEG_VALUE);
            response.addHeader("Cache-Control", "max-age=300");
            StreamUtils.copy(sysFile.getThumbnail(), response.getOutputStream());
            return;
        }
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
    }

    @Operation(summary = "下载附件文件")
    @GetMapping("download/{key}")
    public void download(@PathVariable String key, HttpServletResponse response) throws IOException {
        final SysFile sysFile = sysFileService.getByStorageKey(key);
        if (sysFile == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        InputStream inputStream = fileService.read(sysFile);
        if (inputStream != null) {
            response.setContentType(sysFile.getMimeType());
            ResponseUtils.setAttachmentFileName(sysFile.getFilename());
            StreamUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

}
